package com.mycompany.app.hr.workflow.jbpm.support;

import java.io.InputStream;
import java.util.Arrays;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.configuration.ObjectFactory;
import org.jbpm.configuration.ObjectFactoryParser;
import org.jbpm.graph.def.ProcessDefinition;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;

/**
 * NOTICE:本类代码参考及使用了spring-modules项目中jbpm31的源代码，在本工程中提供jbpm32的支持，
 * 感谢spring-modules项目组
 * 
 * @author Shawn.guo
 */
public class LocalJbpmConfigurationFactoryBean implements InitializingBean,
        DisposableBean, FactoryBean, ApplicationContextAware {

    private static final Log logger = LogFactory
            .getLog(LocalJbpmConfigurationFactoryBean.class);

    private JbpmConfiguration jbpmConfiguration;

    private ObjectFactory objectFactory;

    private Resource configuration;

//    private boolean createSchema = false;
//
//    private boolean dropSchema = false;
    
    private boolean deployProcessDef;

    private String contextName = JbpmContext.DEFAULT_JBPM_CONTEXT_NAME;

    // private Resource[] processDefinitionsResources;

    private ProcessDefinition[] processDefinitions;

    private SessionFactory sessionFactory;

    @SuppressWarnings("unused")
    private ApplicationContext applicationContext;

    /**
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    public void afterPropertiesSet() throws Exception {

        if (configuration == null && objectFactory == null)
            throw new IllegalArgumentException(
                    "configuration or objectFactory property need to be not null");

        ObjectFactory jbpmObjectFactory;

        // 1. create the configuration from the file
        if (configuration != null) {
            logger.info("creating JbpmConfiguration from resource "
                    + configuration.getDescription());
            InputStream in = configuration.getInputStream();
            jbpmObjectFactory = ObjectFactoryParser.parseInputStream(in);
            in.close();
        } else
            jbpmObjectFactory = objectFactory;

        jbpmConfiguration = new JbpmConfiguration(jbpmObjectFactory);

        JbpmContext context = jbpmConfiguration.createJbpmContext(contextName);
        // 2. inject the hibernate session factory if it is the case
        if (this.sessionFactory != null) {
            logger.info("using given Hibernate session factory");
            context.setSessionFactory(this.sessionFactory);
        }

        // 3. execute persistence operations
//        if (createSchema) {
//            logger.info("creating schema");
//            jbpmConfiguration.createSchema(contextName);
//        }

        // if (this.processDefinitions != null
        // || this.processDefinitionsResources != null) {
        if (this.processDefinitions != null&&deployProcessDef) {
            String toString = Arrays.asList(this.processDefinitions).toString();
            logger.info("deploying process definitions:" + toString);

            // deploy the ProcessDefinitions
            for (int i = 0; i < this.processDefinitions.length; i++) {
                context.deployProcessDefinition(processDefinitions[i]);
            }
            if (context != null)
                context.close();
        }
        // if (this.processDefinitionsResources != null) {
        // // ProcessDefinitionFactoryBean factory = new
        // // ProcessDefinitionFactoryBean();
        // // String toString =
        // // Arrays.asList(this.processDefinitionsResources).toString();
        // // logger.info("deploying process definitions (from resources):"
        // // + toString);
        //
        // for (int i = 0; i < this.processDefinitionsResources.length; i++) {
        // //
        // factory.setDefinitionLocation(this.processDefinitionsResources[i]);
        // // factory.afterPropertiesSet();
        // // context.deployProcessDefinition((ProcessDefinition)
        // // factory.getObject());
        // }
        // }
        // }

    }

    /**
     * @see org.springframework.beans.factory.DisposableBean#destroy()
     */
    public void destroy() throws Exception {

//        if (dropSchema) {
//            logger.info("dropping schema");
//            jbpmConfiguration.dropSchema(contextName);
//        }
    }

    /**
     * @see org.springframework.beans.factory.FactoryBean#getObject()
     */
    public Object getObject() throws Exception {

        return jbpmConfiguration;
    }

    // /**
    // * @return Returns the objectFactory.
    // */
    // public ObjectFactory getObjectFactory() {
    //
    // return objectFactory;
    // }

    /**
     * @see org.springframework.beans.factory.FactoryBean#getObjectType()
     */
    public Class getObjectType() {

        return JbpmConfiguration.class;
    }

    /**
     * @see org.springframework.beans.factory.FactoryBean#isSingleton()
     */
    public boolean isSingleton() {

        return true;
    }

    public void setApplicationContext(ApplicationContext applicationContext) {

        this.applicationContext = applicationContext;
        // JbpmApplicationContextLocator.setApplicationContext(applicationContext);
    }

    // ================================================================


    /**
     * @param configuration The configuration to set.
     */
    public void setConfiguration(Resource configuration) {

        this.configuration = configuration;
    }

    /**
     * @param contextName The contextName to set.
     */
    public void setContextName(String contextName) {

        this.contextName = contextName;
    }

    /**
     * @param objectFactory The objectFactory to set.
     */
    // public void setObjectFactory(ObjectFactory objectFactory) {
    //
    // this.objectFactory = objectFactory;
    // }
    /**
     * @param sessionFactory The sessionFactory to set.
     */
    public void setSessionFactory(SessionFactory sessionFactory) {

        this.sessionFactory = sessionFactory;
    }

    /**
     * @return Returns the sessionFactory.
     */
    public SessionFactory getSessionFactory() {

        return sessionFactory;
    }

    /**
     * @return Returns the configuration.
     */
    public Resource getConfiguration() {

        return configuration;
    }

    /**
     * @return Returns the contextName.
     */
    public String getContextName() {

        return contextName;
    }

    public ProcessDefinition[] getProcessDefinitions() {

        return processDefinitions;
    }

    public void setProcessDefinitions(ProcessDefinition[] processDefinitions) {

        this.processDefinitions = processDefinitions;
    }

    public boolean isDeployProcessDef() {
    
        return deployProcessDef;
    }

    public void setDeployProcessDef(boolean deployProcessDef) {
    
        this.deployProcessDef = deployProcessDef;
    }

}
